/**
 * UX used to provide a spotlight around a specified component/element.
 */
Ext.define('Ext.ux.Spotlight', {
			/**
			 * @private The baseCls for the spotlight elements
			 */
			baseCls : 'x-spotlight',

			/**
			 * @cfg animate {Boolean} True to animate the spotlight change
			 *      (defaults to true)
			 */
			animate : true,

			/**
			 * @cfg duration {Integer} The duration of the animation, in
			 *      milliseconds (defaults to 250)
			 */
			duration : 250,

			/**
			 * @cfg easing {String} The type of easing for the spotlight
			 *      animatation (defaults to null)
			 */
			easing : null,

			/**
			 * @private True if the spotlight is active on the element
			 */
			active : false,

			constructor : function(config) {
				Ext.apply(this, config);
			},

			/**
			 * Create all the elements for the spotlight
			 */
			createElements : function() {
				var me = this, baseCls = me.baseCls, body = Ext.getBody();

				me.right = body.createChild({
							cls : baseCls
						});
				me.left = body.createChild({
							cls : baseCls
						});
				me.top = body.createChild({
							cls : baseCls
						});
				me.bottom = body.createChild({
							cls : baseCls
						});

				me.all = Ext.create('Ext.CompositeElement', [me.right, me.left,
								me.top, me.bottom]);
			},

			/**
			 * Show the spotlight
			 */
			show : function(el, callback, scope) {
				var me = this;

				// get the target element
				me.el = Ext.get(el);

				// create the elements if they don't already exist
				if (!me.right) {
					me.createElements();
				}

				if (!me.active) {
					// if the spotlight is not active, show it
					me.all.setDisplayed('');
					me.active = true;
					Ext.EventManager.onWindowResize(me.syncSize, me);
					me.applyBounds(me.animate, false);
				} else {
					// if the spotlight is currently active, just move it
					me.applyBounds(false, false);
				}
			},

			/**
			 * Hide the spotlight
			 */
			hide : function(callback, scope) {
				var me = this;

				Ext.EventManager.removeResizeListener(me.syncSize, me);

				me.applyBounds(me.animate, true);
			},

			/**
			 * Resizes the spotlight with the window size.
			 */
			syncSize : function() {
				this.applyBounds(false, false);
			},

			/**
			 * Resizes the spotlight depending on the arguments
			 * 
			 * @param {Boolean}
			 *            animate True to animate the changing of the bounds
			 * @param {Boolean}
			 *            reverse True to reverse the animation
			 */
			applyBounds : function(animate, reverse) {
				var me = this, box = me.el.getBox(),
				// get the current view width and height
				viewWidth = Ext.Element.getViewWidth(true), viewHeight = Ext.Element
						.getViewHeight(true), i = 0, config = false, from, to, clone;

				// where the element should start (if animation)
				from = {
					right : {
						x : box.right,
						y : viewHeight,
						width : (viewWidth - box.right),
						height : 0
					},
					left : {
						x : 0,
						y : 0,
						width : box.x,
						height : 0
					},
					top : {
						x : viewWidth,
						y : 0,
						width : 0,
						height : box.y
					},
					bottom : {
						x : 0,
						y : (box.y + box.height),
						width : 0,
						height : (viewHeight - (box.y + box.height)) + 'px'
					}
				};

				// where the element needs to finish
				to = {
					right : {
						x : box.right,
						y : box.y,
						width : (viewWidth - box.right) + 'px',
						height : (viewHeight - box.y) + 'px'
					},
					left : {
						x : 0,
						y : 0,
						width : box.x + 'px',
						height : (box.y + box.height) + 'px'
					},
					top : {
						x : box.x,
						y : 0,
						width : (viewWidth - box.x) + 'px',
						height : box.y + 'px'
					},
					bottom : {
						x : 0,
						y : (box.y + box.height),
						width : (box.x + box.width) + 'px',
						height : (viewHeight - (box.y + box.height)) + 'px'
					}
				};

				// reverse the objects
				if (reverse) {
					clone = Ext.clone(from);
					from = to;
					to = clone;
				}

				if (animate) {
					Ext.Array.forEach(['right', 'left', 'top', 'bottom'],
							function(side) {
								me[side].setBox(from[side]);
								me[side].animate({
											duration : me.duration,
											easing : me.easing,
											to : to[side]
										});
							}, this);
				} else {
					Ext.Array.forEach(['right', 'left', 'top', 'bottom'],
							function(side) {
								me[side]
										.setBox(Ext.apply(from[side], to[side]));
								me[side].repaint();
							}, this);
				}
			},

			/**
			 * Removes all the elements for the spotlight
			 */
			destroy : function() {
				var me = this;

				Ext.destroy(me.right, me.left, me.top, me.bottom);
				delete me.el;
				delete me.all;
			}
		});
